//********************************************************************
//	created:	19:10:2011   15:35
//	filename: 	rssservice.h
//	author:		tiamo
//	purpose:	rss service
//********************************************************************

#pragma once

namespace rss
{
	//
	// item
	//
	class RSSItem
	{
	public:
		//
		// constructor
		//
		RSSItem()															{}

		//
		// destructor
		//
		~RSSItem()															{}

		//
		// copy constructor
		//
		RSSItem(RSSItem const& rhs) : mId(rhs.mId), mTitle(rhs.mTitle), mLink(rhs.mLink), mCategory(rhs.mCategory), mCategoryId(rhs.mCategoryId), mPublishDate(rhs.mPublishDate), mDescription(rhs.mDescription), mGuid(rhs.mGuid), mEnclosure(rhs.mEnclosure), mEnclosureLength(rhs.mEnclosureLength){}

		//
		// move constructor
		//
		RSSItem(RSSItem&& rhs) : mId(rhs.mId), mTitle(std::move(rhs.mTitle)), mLink(std::move(rhs.mLink)), mCategory(std::move(rhs.mCategory)), mCategoryId(rhs.mCategoryId), mPublishDate(rhs.mPublishDate), mDescription(std::move(rhs.mDescription)), mGuid(std::move(rhs.mGuid)), mEnclosure(std::move(rhs.mEnclosure)), mEnclosureLength(rhs.mEnclosureLength){}

		//
		// assignment
		//
		RSSItem& operator=(RSSItem const& rhs)								{if(this != &rhs) {mId = rhs.mId; mTitle = rhs.mTitle; mLink = rhs.mLink; mCategory = rhs.mCategory; mCategoryId = rhs.mCategoryId; mPublishDate = rhs.mPublishDate, mDescription = rhs.mDescription; mGuid = rhs.mGuid; mEnclosure = rhs.mEnclosure; mEnclosureLength = rhs.mEnclosureLength;} return *this;}

		//
		// move assignment
		//
		RSSItem& operator=(RSSItem&& rhs)									{if(this != &rhs) {mId = rhs.mId; mTitle = std::move(rhs.mTitle); mLink = std::move(rhs.mLink); mCategory = std::move(rhs.mCategory); mCategoryId = rhs.mCategoryId; mPublishDate = rhs.mPublishDate, mDescription = std::move(rhs.mDescription); mGuid = std::move(rhs.mGuid); mEnclosure = std::move(rhs.mEnclosure); mEnclosureLength = rhs.mEnclosureLength;} return *this;}

		//
		// compare
		//
		bool operator==(RSSItem const& rhs) const							{return (mId && rhs.mId) ? (mId == rhs.mId) : (mTitle == rhs.mTitle && mLink == rhs.mLink && mCategory == rhs.mCategory && mCategoryId == rhs.mCategoryId && mPublishDate == rhs.mPublishDate /*&& mDescription == rhs.mDescription*/ && mGuid == rhs.mGuid && mEnclosure == rhs.mEnclosure && mEnclosureLength == rhs.mEnclosureLength);}

		//
		// compare
		//
		bool operator!=(RSSItem const& rhs) const							{return !(*this == rhs);}

	public:
		//
		// id
		//
		uint32_t															mId;

		//
		// title
		//
		UniString															mTitle;

		//
		// link
		//
		UniString															mLink;

		//
		// category
		//
		UniString															mCategory;

		//
		// category
		//
		uint32_t															mCategoryId;

		//
		// publish date
		//
		uint32_t															mPublishDate;

		//
		// description
		//
		UniString															mDescription;

		//
		// guid
		//
		UniString															mGuid;

		//
		// enclosure url
		//
		UniString															mEnclosure;

		//
		// enclosure length
		//
		uint64_t															mEnclosureLength;
	};

	//
	// item list
	//
	typedef std::list<RSSItem>												RSSItemList;

	//
	// rss
	//
	class Service : public ::Service
	{
	public:
		//
		// new item callback param
		//
		typedef std::function<void(Service*, RSSItemList const&)>			NewItemCallback;

	public:
		//
		// constructor
		//
		Service(UniString const& name, mysql::Database& database) : ::Service(name, database) {}

		//
		// destructor
		//
		virtual ~Service()													{}

		//
		// set new item callback
		//
		void setNewItemCallback(NewItemCallback&& callback)					{mNewItemCallback = std::move(callback);}

		//
		// get table name
		//
		UniString const& getTableName() const								{return mTableName;}

	private:
		//
		// initialize
		//
		virtual void initialize();

		//
		// build item list
		//
		RSSItemList buildItemList(utils::DataBuffer&& rssContent);

		//
		// compute added item list
		//
		RSSItemList buildAddedItemList(RSSItemList const& oldList, RSSItemList& newList);

		//
		// start refresh timer
		//
		void startRefreshTimer(uint32_t delayTime);

		//
		// load item list
		//
		void onLoadItemList(utils::BaseRequest* theRequest);

		//
		// get content timer
		//
		bool onGetContentTimer(uint32_t elapsedTime);

		//
		// get content
		//
		void onGetContent(utils::BaseRequest* theRequest);

		//
		// insert new item
		//
		void onInsertNewItem(utils::BaseRequest* theRequest);

	private:
		//
		// url
		//
		UniString															mContentURL;

		//
		// table name
		//
		UniString															mTableName;

		//
		// schedule delay time on failure
		//
		uint32_t															mFailureDelayTime;

		//
		// schedule delay time on success
		//
		uint32_t															mSuccessDelayTime;

		//
		// current item list
		//
		RSSItemList															mItemList;

		//
		// new item callback
		//
		NewItemCallback														mNewItemCallback;
	};
};
